﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace Codemonk.Soya
{
    public class WorkbookParser : IWorkbookParser
    {
        private DocumentDescription description;

        public string ConfigFilePath { get; set; }

        public IWorkbookReader Reader { get; set; }

        public IStringConverter Converter { get; set; }

        private void CheckStatus()
        {
            if (string.IsNullOrWhiteSpace(ConfigFilePath)) throw new Exception("未设置配置文件");
            if (Reader == null) throw new Exception("未设置读取器");
            if (Converter == null) throw new Exception("未设置转换器");
            description = new DocumentDescription
            {
                Converter = Converter,
                FileName = ConfigFilePath
            };
        }

        public IDictionary<string, List<IDictionary<string, object>>> Parse(string filename)
        {
            CheckStatus();
            try
            {
                return InnerParse(filename);
            }
            catch
            {
                return null;
            }
        }

        private IDictionary<string, List<IDictionary<string, object>>> ReadPaging(int sheetIndex)
        {
            var shemes = description.Shemes;
            var rowCount = Reader.GetRowCount(sheetIndex);
            IDictionary<string, List<IDictionary<string, object>>> output = new Dictionary<string, List<IDictionary<string, object>>>();
            foreach (var sheme in shemes)
            {
                int lastRowIndex = 0;
                var targetname = sheme.TargetName;
                IDictionary<string, Dictionary<string, List<object>>> complexValues = new Dictionary<string, Dictionary<string, List<object>>>();
                List<IDictionary<string, object>> results = new List<IDictionary<string, object>>();
                var rules = sheme.ReadRules;
                Dictionary<string, object> dict = new Dictionary<string, object>();
                int rowIndex = -1;
                bool lastIsStartRow = false;
                bool isNewPage = false;
                Dictionary<int, bool> startRowDict = new Dictionary<int, bool>();
                while (rowIndex++ < rowCount)
                {
                    var columnIndex = 0;
                    string cellValue = null;

                    #region 新行
                    if (startRowDict.Count > 0 && !(startRowDict.Where(m => !m.Value).Select(m => !m.Value).FirstOrDefault()))
                    {
                        results.Add(dict);
                        startRowDict = startRowDict.ToDictionary(k => k.Key, v => false);
                        dict = new Dictionary<string, object>();
                    }
                    if (startRowDict.Count == 0 && lastIsStartRow && dict.Count > 0)
                    {
                        results.Add(dict);
                        dict = new Dictionary<string, object>();
                        lastIsStartRow = false;
                    }

                    #endregion

                    #region 划分区域

                    if (description.Paging == null)
                    {
                        isNewPage = true;
                        lastRowIndex = rowIndex;
                        lastIsStartRow = false;
                    }
                    else
                    {
                        columnIndex = description.Paging.ColumnIndex;
                        cellValue = (Reader.GetValue(sheetIndex, rowIndex, columnIndex) + "").Trim();
                        if (description.Paging.Regex.IsMatch(cellValue))
                        {
                            lastRowIndex = rowIndex;
                            lastIsStartRow = false;
                            isNewPage = true;
                            if (complexValues.Count > 0) complexValues = new Dictionary<string, Dictionary<string, List<object>>>();
                            if (dict.Count > 0)
                            {
                                results.Add(dict);
                                startRowDict = startRowDict.ToDictionary(k => k.Key, v => false);
                                dict = new Dictionary<string, object>();
                            }
                        }
                        else isNewPage = false;
                    }
                    #endregion

                    #region 规则循环
                    int rindex = 0;
                    foreach (var rule in rules)
                    {
                        rindex++;
                        if (!startRowDict.ContainsKey(rindex)) startRowDict[rindex] = false;
                        var rule_RowIndex = rule.Location.RowIndex;
                        columnIndex = rule.Location.ColumnIndex;
                        if (rule_RowIndex != int.MinValue)
                        {
                            cellValue = (Reader.GetValue(sheetIndex, rule_RowIndex, columnIndex) + "").Trim();
                        }
                        else if ((rule_RowIndex = rule.Location.StartRow) != int.MinValue)
                        {
                            if (rowIndex < rule_RowIndex + lastRowIndex) continue;
                            else
                            {
                                cellValue = (Reader.GetValue(sheetIndex, rowIndex, columnIndex) + "").Trim();
                            }
                        }

                        #region  简单格
                        var sevaluation = rule.Evaluation as SimpleEvaluation;
                        if (sevaluation != null)
                        {
                            var match = sevaluation.Regex.Match(cellValue);
                            if (match.Success)
                            {
                                var reduces = sevaluation.Reduces;
                                foreach (var reduce in reduces)
                                {
                                    object value = null;
                                    var tvalue = match.Groups[reduce.GroupIndex].Value;
                                    if (string.IsNullOrWhiteSpace(tvalue) && !reduce.CanNull) { break; }
                                    try { value = Converter.As(reduce.Type, tvalue.Trim(), reduce.DefaultValue); }
                                    catch
                                    {
                                        value = reduce.DefaultValue;
                                        if (!reduce.CanNull) break;
                                    }
                                    startRowDict[rindex] = true;
                                    dict[reduce.Property] = value;
                                }
                            }
                        }
                        #endregion
                        #region 复杂格
                        var cevaluation = rule.Evaluation as ComplexEvaluation;
                        if (cevaluation != null)
                        {
                            var c_targetname = cevaluation.TargetName;
                            if (!complexValues.ContainsKey(c_targetname)) complexValues[c_targetname] = new Dictionary<string, List<object>>();
                            var c_dict = complexValues[c_targetname];
                            var reference = cevaluation.Reference;
                            var r_value = (Reader.GetValue(sheetIndex, rowIndex, reference.ColumnIndex) + "").Trim();
                            if (!reference.Regex.IsMatch(r_value)) continue;
                            var match = cevaluation.Regex.Match(cellValue);
                            if (match.Success)
                            {
                                var reduces = cevaluation.Reduces;
                                foreach (var reduce in reduces)
                                {
                                    object value = null;
                                    var tvalue = match.Groups[reduce.GroupIndex].Value;
                                    if (string.IsNullOrWhiteSpace(tvalue) && !reduce.CanNull) { break; }
                                    try { value = Converter.As(reduce.Type, tvalue.Trim(), reduce.DefaultValue); }
                                    catch { if (!reduce.CanNull) break; }
                                    if (!reduce.CanNull && value == null) break;
                                    if (!c_dict.ContainsKey(reduce.Property)) c_dict[reduce.Property] = new List<object>();
                                    var list = c_dict[reduce.Property];
                                    if (list.Contains(value)) continue;
                                    list.Add(value);
                                    if (isNewPage) startRowDict[rindex] = true;
                                }
                            }
                        }
                        #endregion
                    }
                    #endregion

                    #region 复杂格填充
                    if (dict.Count > 0)
                    {
                        if (complexValues != null && complexValues.Count > 0)
                        {
                            var collection = complexValues;
                            foreach (var item in collection) dict[item.Key] = item.Value;
                        }
                    }
                    #endregion
                }
                if (dict.Count > 0)
                {
                    results.Add(dict);
                    dict = new Dictionary<string, object>();
                }
                output.Add(targetname, results);
            }

            return output;
        }

        private IDictionary<string, List<IDictionary<string, object>>> InnerParse(string filename)
        {
            Reader.FileName = filename;
            var sheetCount = Reader.GetSheetCount();
            for (int sheetIndex = 0; sheetIndex < sheetCount; sheetIndex++)
            {
                var sheetName = Reader.GetSheetName(sheetIndex);
                if (description.SheetLimit != null && !description.SheetLimit.IsMatch(sheetName)) continue;
                return ReadPaging(sheetIndex);
            }
            return null;
        }

    }
}
